package cmd

import (
	"fmt"
	"sort"

	"github.com/gookit/color"
	"github.com/gookit/goutil/dump"
	"starsine.cn/appTpl/cmn/config/aconf"
	"starsine.cn/appTpl/cmn/config/hconf"
	"starsine.cn/appTpl/cmn/gcli/v3"
	peerclient "starsine.cn/appTpl/svclog/peers/client"
	"starsine.cn/appTpl/svclog/src/fe/chan2client"
	"starsine.cn/appTpl/svclog/src/fe/token"
	"starsine.cn/appTpl/svclog/src/fe/ws-server"
	festrung "starsine.cn/appTpl/svclog/src/logproc/fe-strung"
	"starsine.cn/appTpl/svclog/src/svclogpubsub"
	svcclientmng "starsine.cn/appTpl/svcpeers/client"
	"starsine.cn/appTpl/svcregistry/grpc/handler"
)

// ///////// "github.com/gookit/gcli/v3"
var gCliApp *gcli.App = nil

func GCliStart() *gcli.App {
	gCliApp = gcli.NewApp()
	gCliApp.Version = "1.0.0"
	gCliApp.Desc = "appTpl app commands."

	gCliApp.Add(Example)
	gCliApp.Add(Help)
	gCliApp.Add(TestXXX)
	gCliApp.Add(DumpConfig)
	gCliApp.Add(DumpSvcInfo)
	gCliApp.Add(DumpSvcDepStatus)
	gCliApp.Add(DumpWs2ClientMap)
	gCliApp.Add(DumpTokens)
	gCliApp.Add(DumpFeStrung)
	gCliApp.Add(DumpWSConnMap)
	gCliApp.Add(DumpSvcClientMng)
	gCliApp.Add(DumpSvcLogPubsub)

	return gCliApp
}

func GCliExe(c string) {
	gCliApp.ExecCmd(c)
}

// The string flag list, implemented flag.Value interface
type Names []string

func (ns *Names) String() string {
	return fmt.Sprint(*ns)
}

func (ns *Names) Set(value string) error {
	*ns = append(*ns, value)
	return nil
}

// options for the command
var exampleOpts = struct {
	id      int
	c       string
	dir     string
	opt     string
	showErr bool
	names   Names
}{}

// Example command definition
var Example = &gcli.Command{
	Func:    exampleExecute,
	Name:    "example",
	Aliases: []string{"module-exp", "exp", "ex"},
	Desc:    "this is command description message",
	// {$binName} {$cmd} is help vars. '{$cmd}' will replace to 'example'
	Examples: `
  {$binName} {$cmd} --id 12 -c val ag0 ag1
  <cyan>{$fullCmd} --names tom --names john -n c</> 	test use special option
`,
	Config: func(c *gcli.Command) {
		// bind options
		c.IntOpt(&exampleOpts.id, "id", "", 2, "the id option")
		c.BoolOpt(&exampleOpts.showErr, "err", "e", false, "display error example")
		c.StrOpt(&exampleOpts.c, "config", "c", "value", "the config option")
		// notice `DIRECTORY` will replace to option value type
		c.StrOpt(&exampleOpts.dir, "dir", "d", "", "the `DIRECTORY` option")
		// setting option name and short-option name
		c.StrOpt(&exampleOpts.opt, "opt", "o", "", "the option message")
		// setting a special option var, it must implement the flag.Value interface
		c.VarOpt(&exampleOpts.names, "names", "n", "the option message")

		// bind args with names
		c.AddArg("arg0", "the first argument, is required", false)
		c.AddArg("arg1", "the second argument, is required", false)
		c.AddArg("arg2", "the optional argument, is optional")
		c.AddArg("arrArg", "the array argument, is array", false, false)
	},
}

// command running
// example run:
//
//	go run ./_examples/cliapp.go ex -c some.txt -d ./dir --id 34 -n tom -n john val0 val1 val2 arrVal0 arrVal1 arrVal2
func exampleExecute(c *gcli.Command, args []string) (string, error) {
	color.Infoln("hello, in example command")

	if exampleOpts.showErr {
		return "", c.Errorf("OO, An error has occurred!!")
	}

	magentaln := color.Magenta.Println

	color.Cyanln("All Aptions:")
	// fmt.Printf("%+v\n", exampleOpts)
	dump.V(exampleOpts)

	color.Cyanln("Remain Args:")
	// fmt.Printf("%v\n", args)
	dump.P(args)

	magentaln("Get arg by name:")
	arr := c.Arg("arg0")
	fmt.Printf("named arg '%s', value: %#v\n", arr.Name, arr.Value)

	magentaln("All named args:")
	for _, arg := range c.Args() {
		fmt.Printf("- named arg '%s': %+v\n", arg.Name, arg.Value)
	}

	return "example output", nil
}

var Help = &gcli.Command{
	Func:    helpExecute,
	Name:    "help",
	Aliases: []string{"h", "hlp"},
	Desc:    "show command list and command summary.",
	Examples: `
	help
`,
	Config: func(c *gcli.Command) {
		c.AddArg("arg0", "command name", false)
	},
}

func helpExecute(c *gcli.Command, args []string) (string, error) {
	info := ""
	magentaln := color.Magenta.Println
	color.Infoln("HELP")

	arr := c.Arg("arg0")
	if arr.Value.String() != "" {
		gCliApp.ShowCommandHelp(arr.Value.String())
		c.Arg("arg0").SetValue("")
		return "", nil
	}

	color.Cyanln("All Commands:")
	cmdList := []string{}
	for k, v := range gCliApp.Commands() {
		cmdList = append(cmdList, fmt.Sprintf("%-20s: %s %s", k, v.Aliases, v.Desc))
	}
	sort.Slice(cmdList, func(i, j int) bool {
		return cmdList[i] < cmdList[j]
	})
	for c, cmdstr := range cmdList {
		info += fmt.Sprintf("(%-2d) %s\n", c, cmdstr)
	}

	magentaln(info)
	return info, nil
}

var TestXXX = &gcli.Command{
	Func:    execTestXXX,
	Name:    "test",
	Aliases: []string{"tst"},
	Desc:    "test any what you want",
	Examples: `
	test
	tst
`,
	Config: func(c *gcli.Command) {
	},
}

func execTestXXX(c *gcli.Command, args []string) (string, error) {
	color.Infoln("%s --->", c.Name)
	magentaln := color.Magenta.Println

	out := ""
	magentaln(out)
	return out, nil
}

var DumpConfig = &gcli.Command{
	Func:    execDumpConfig,
	Name:    "dumpconfig",
	Aliases: []string{"dpcfg"},
	Desc:    "dump all config information",
	Examples: `
	dumpconfig
	dpcfg
`,
	Config: func(c *gcli.Command) {
	},
}

func execDumpConfig(c *gcli.Command, args []string) (string, error) {
	color.Infoln("dumpconfig --->")
	magentaln := color.Magenta.Println

	out := ""
	out += hconf.DumpConfig()
	conf := aconf.DumpConfigs()
	for k, v := range conf {
		out += fmt.Sprintf("%s:%v\n", k, v)
	}

	magentaln(out)

	return out, nil
}

var DumpSvcInfo = &gcli.Command{
	Func:    execDumpSvcInfo,
	Name:    "dumpsvcinfo",
	Aliases: []string{"svcinfo"},
	Desc:    "dump service information",
	Examples: `
	dumpsvcinfo
	svcinfo
`,
	Config: func(c *gcli.Command) {
	},
}

func execDumpSvcInfo(c *gcli.Command, args []string) (string, error) {
	color.Infoln("dump service information --->")
	magentaln := color.Magenta.Println

	out := handler.GetSvcInfo()

	magentaln(out)

	return out, nil
}

var DumpSvcDepStatus = &gcli.Command{
	Func:    execDumpSvcDepStatus,
	Name:    "dumpsvcdepstatus",
	Aliases: []string{"svcdeps"},
	Desc:    "dump service information",
	Examples: `
	dumpsvcdepstatus
	svcdeps
`,
	Config: func(c *gcli.Command) {
	},
}

func execDumpSvcDepStatus(c *gcli.Command, args []string) (string, error) {
	color.Infoln("dump service dependence status --->")
	magentaln := color.Magenta.Println

	out := peerclient.DumpSvcDepStatus()

	magentaln(out)

	return out, nil
}

var DumpWs2ClientMap = &gcli.Command{
	Func:    execDumpWs2ClientMap,
	Name:    "dumpws2clientmap",
	Aliases: []string{"dpw2c"},
	Desc:    "dump front end websocket connection to client map",
	Examples: `
	dumpws2clientmap
	dpw2c
`,
	Config: func(c *gcli.Command) {
	},
}

func execDumpWs2ClientMap(c *gcli.Command, args []string) (string, error) {
	color.Infoln("dumpws2clientmap --->")
	magentaln := color.Magenta.Println

	out := chan2client.DumpWs2ClientMap()

	magentaln(out)

	return out, nil
}

var DumpTokens = &gcli.Command{
	Func:    execDumpTokens,
	Name:    "dumptokens",
	Aliases: []string{"dptoks"},
	Desc:    "dump all tokens in the cluster",
	Examples: `
	dumptokens
	dptoks
`,
	Config: func(c *gcli.Command) {
	},
}

func execDumpTokens(c *gcli.Command, args []string) (string, error) {
	color.Infoln("dumptokens --->")
	magentaln := color.Magenta.Println

	out := token.Dump()

	magentaln(out)

	return out, nil
}

var DumpFeStrung = &gcli.Command{
	Func:    execDumpFeStrung,
	Name:    "dumpfestrung",
	Aliases: []string{"dpfstrung"},
	Desc:    "dump fe-strung map data",
	Examples: `
	dumpfestrung
	dpfstrung
`,
	Config: func(c *gcli.Command) {
	},
}

func execDumpFeStrung(c *gcli.Command, args []string) (string, error) {
	color.Infoln("dumpfestrung --->")
	magentaln := color.Magenta.Println

	out := festrung.Dump()

	magentaln(out)

	return out, nil
}

var DumpWSConnMap = &gcli.Command{
	Func:    execDumpWSConnMap,
	Name:    "dumpwsconnmap",
	Aliases: []string{"dpwsmap"},
	Desc:    "dump front end ws connect map infomation",
	Examples: `
	dumpwsconnmap
	dpwsmap
`,
	Config: func(c *gcli.Command) {
	},
}

func execDumpWSConnMap(c *gcli.Command, args []string) (string, error) {
	color.Infoln("dumpwsconnmap --->")
	magentaln := color.Magenta.Println

	out := ws.Dump()

	magentaln(out)

	return out, nil
}

var DumpSvcClientMng = &gcli.Command{
	Func:    execDumpSvcClientMng,
	Name:    "dumpsvcclientmng",
	Aliases: []string{"dpcmng"},
	Desc:    "dump SvcClientMng map data",
	Examples: `
	dumpsvcclientmng
	dpcmng
`,
	Config: func(c *gcli.Command) {
	},
}

func execDumpSvcClientMng(c *gcli.Command, args []string) (string, error) {
	color.Infoln("dumpsvcclientmng --->")
	magentaln := color.Magenta.Println

	out := svcclientmng.Dump()

	magentaln(out)

	return out, nil
}

var DumpSvcLogPubsub = &gcli.Command{
	Func:    execDumpSvcLogPubsub,
	Name:    "dumpsvclogpubsub",
	Aliases: []string{"dpps"},
	Desc:    "dump svclog pubsub map info data ",
	Examples: `
	dumpsvclogpubsub
	dpps
`,
	Config: func(c *gcli.Command) {
	},
}

func execDumpSvcLogPubsub(c *gcli.Command, args []string) (string, error) {
	color.Infoln("dumpsvclogpubsub --->")
	magentaln := color.Magenta.Println

	out := svclogpubsub.DumpPubSub()

	magentaln(out)

	return out, nil
}
